#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>

#include <boost/filesystem.hpp>

#include "Log.hpp"
#include "FileUtil.hpp"

using namespace LogArea;

#define SEP "\3"

const std::string src_path = "data/input/";                       // html所在源文件
const std::string output = "data/processed_html/processed.txt"; // 放置处理后的html的文件

typedef struct DocInfo
{
    std::string title;   // 文档标题
    std::string content; // 文档内容
    std::string url;     // 该文档在官网中的url
} DocInfo_t;



bool EnumHtml(const std::string &stc_path, std::vector<std::string> &files_list);
bool ParseHtml(const std::vector<std::string> &files_list, std::vector<DocInfo> &results);
bool SaveHtml(const std::vector<DocInfo> &results, const std::string &output);

// 递归式地把src_path中的文件带路径地保存到files_list中,方便后面读取
bool EnumHtml(const std::string &stc_path, std::vector<std::string> &files_list)
{
    boost::filesystem::path root_path(stc_path); // 获取路径文件结构
    if (!boost::filesystem::exists(root_path))   // 判断路径是否存在
    {
        LogArea::LOG(LogLevel::ERROR) << src_path << "No exitst";
        return false;
    }

    // 定义一个空的迭代器,用来判断递归结束
    boost::filesystem::recursive_directory_iterator end;
    for (boost::filesystem::recursive_directory_iterator begin(root_path); begin != end; begin++) // 递归遍历
    {
        // 判断文件是否是以.html为结尾的普通文件
        if (!boost::filesystem::is_regular_file(*begin) || begin->path().extension() != ".html")
            continue;

        // 走到这说明当前文件一定是一个合法的,以.html为结尾的普通网页文件
        // For Debug
        // LogArea::LOG(LogLevel::DEBUG) << begin->path().string();
        // std::cout << std::endl;
        files_list.emplace_back(begin->path().string());
    }

    return true;
}

// 解析文档标题
static bool ParseTitle(const std::string &result, std::string *title)
{
    size_t begin = result.find("<title>");
    if (begin == std::string::npos)
    {
        LogArea::LOG(LogLevel::INFO) << "Not found <title>";
        return false;
    }

    size_t end = result.find("</title>");
    if (end == std::string::npos)
    {
        LogArea::LOG(LogLevel::INFO) << "Not found </title>";
        return false;
    }

    if (begin > end)
    {
        LogArea::LOG(LogLevel::ERROR) << "error";
        return false;
    }

    *title = result.substr(begin, end - begin);
    return true;
}

static bool ParseContent(const std::string &result, std::string *content)
{
    enum status
    {
        LABLE,
        CONTENT
    };

    enum status s = LABLE;
    for (char c : result)
    {
        switch (s)
        {
        case LABLE:
            if (c == '>')
                s = CONTENT;
            break;
        case CONTENT:
            if (c == '<')
                s = LABLE; // 可能有多个标签
            else
            {
                if (c == '\n')
                    c = ' ';
                content->push_back(c);
            }
            break;
        default:
            break;
        }
    }

    return true;
}

// 将拼接官网中html文件的路径
static bool ParseUrl(const std::string &file, std::string *url)
{
    // https://www.boost.org/doc/libs/1_87_0/doc/html/array.html
    // 截取 file data/input/ 以后的内容就是官网中 array.html 的内容
    std::string url_head = "https://www.boost.org/doc/libs/1_87_0/doc/html/";
    std::string url_tail = file.substr(src_path.size()); // 截取 file 中 data/input 后面的内容,就是具体的html文件

    *url = url_head + url_tail;
    return true;
}

// 读取files_list中的内容,并解析为DocInfo格式(去标签)
bool ParseHtml(const std::vector<std::string> &files_list, std::vector<DocInfo> &results)
{
    for (const std::string &file : files_list)
    {
        std::string result;

        if (!UtilArea::FileUtil::ReadUtil(file, result))
            continue;

        // 解析文档
        DocInfo doc;

        // 解析文档标题
        if (!ParseTitle(result, &doc.title))
            continue;

        // 解析文档内容
        if (!ParseContent(result, &doc.content))
            continue;

        if (!ParseUrl(file, &doc.url))
            continue;

        // 走到这说明文档解析成功,相关字段都保存到了doc中
        results.emplace_back(doc);

        // For Debug
        // LogArea::LOG(LogLevel::DEBUG) << "doc.title: " << doc.title;
        // std::cout<<std::endl;
        // LogArea::LOG(LogLevel::DEBUG)<< "doc.content: " << doc.content;
        // std::cout<<std::endl;
        // LogArea::LOG(LogLevel::DEBUG)<< "doc.url: " << doc.url;
        // std::cout << std::endl;
        // break;
    }
    return true;
}

// 把解析完毕的各个文档的内容,写入到output中,用\3作为每个文档的分隔符
bool SaveHtml(const std::vector<DocInfo> &results, const std::string &output)
{
    // 以二进制形式打开output文件进行写入
    std::ofstream out(output,std::ios::out | std::ios::binary);
    if(!out.is_open())
    {
        LogArea::LOG(LogLevel::ERROR)<<"Open file: "<<output<<"error";
        return false;
    }

    // 封装为 title\3content\3url\n 格式
    for(auto& it : results)
    {
        std::string out_string;
        out_string = it.title;
        out_string += SEP;
        out_string += it.content;
        out_string += SEP;
        out_string += it.url;
        out_string += '\n';

        out.write(out_string.c_str(),out_string.size());
    }
    return true;
}

int main()
{
    std::vector<std::string> files_list; // 存放src_html

    // 第一步: 递归式地把src_path中的文件带路径地保存到files_list中,方便后面读取
    if (!EnumHtml(src_path, files_list))
    {
        LogArea::LOG(LogLevel::ERROR) << "Enum src_path to files_html error";
        return 1;
    }

    // 第二步: 读取files_list中的内容,并解析为DocInfo格式
    std::vector<DocInfo_t> results;
    if (!ParseHtml(files_list, results))
    {
        LogArea::LOG(LogLevel::ERROR) << "Parser files_html to results error";
        return 2;
    }

    // 第三步: 把解析完毕的各个文档的内容,写入到output中,用\3作为每个文档的分隔符
    if (!SaveHtml(results, output))
    {
        LogArea::LOG(LogLevel::ERROR) << "SaveHtml results to output error";
        return 3;
    }

    return 0;
}
